package MULE.Model.Logic;

import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;

import MULE.Model.*;
import MULE.Model.Panel.MapPanel;

/**
 * Logic module responsible for the property selection phase of MULE.
 * 
 * @author jstep
 */
public class PropertySelectionLogic extends MulePresenter implements
		KeyListener {

	private final int FREE_LAND_GRANTS = 2;
	private final int PASS_OPT_KEYCODE = 32; // Space bar key code.
	private final String DIALOG_TITLE = "Property Selection";

	private Game game;
	private ArrayList<Player> players;
	private Player currentPlayer;
	private boolean freeGrant;
	private int currentRound;
	private boolean stillPurchasing;

	/**
	 * Creates a new logic module responsible for the property selection phase.
	 * 
	 * @param view
	 *            This presenter's associated view.
	 */
	public PropertySelectionLogic(MapPanel view) {
		super(view);
		this.game = MuleDriver.getGame();
		this.freeGrant = true;
		// Set key listener.
		view.setKeyListener(this);
		view.requestFocusInWindow();
	}

	/**
	 * Starts the property selection process.
	 */
	public void enterPropertySelectionPhase() {
		this.players = game.getPlayers(); // TODO use turn order?
		this.currentPlayer = players.get(0);
		this.currentRound = 1;
		this.stillPurchasing = false;
		// Set resource tile listeners.
		MapPanel mapPanel = (MapPanel) this.view;
		mapPanel.addTownListener(null);
		mapPanel.setResourceTileListener(this);
		// Add key listener for pass option.
		mapPanel.setKeyListener(this);
		mapPanel.requestFocusInWindow();
		// Update UI.
		for (Player p : players) {
			MuleDriver.updateScore(p);
		}
		updateDialogue();
	}

	/**
	 * Generates a string describing the current status of property selection.
	 * 
	 * @return Status of property selection as a string.
	 */
	public void updateDialogue() {
		// Round type (free or purchase).
		String dialogueText = freeGrant ? "Land grant #" : "Land purchase #";
		// Round number.
		dialogueText += freeGrant ? currentRound : currentRound
				- FREE_LAND_GRANTS;
		// Player name.
		dialogueText += ": " + currentPlayer.getName() + "'s turn. ";
		// Instruction to player.
		dialogueText += freeGrant ? "Claim a free tile" : "Purchase a tile";
		dialogueText += ", or press spacebar to pass.";
		// Set dialogue text.
		MuleDriver.setCaptionText(dialogueText);
	}

	/**
	 * Goes to the next turn in property selection. Player, round number, and
	 * selection type (free or purchase), and game caption are updated.
	 */
	public void nextTurn() {
		// Increment current player. Player order is preserved in player list.
		int pIndex = players.indexOf(currentPlayer);
		int newPIndex = (pIndex == (players.size() - 1)) ? 0 : ++pIndex;
		currentPlayer = players.get(newPIndex);
		// Check if all players have been cycled through (one round).
		if (newPIndex == 0) {
			++currentRound;
			// Check if free land grants remain.
			if (currentRound > FREE_LAND_GRANTS) {
				freeGrant = false;
				// End property selection phase if all players have passed.
				if (!stillPurchasing) {
					endPropertySelectionAndStartGame();
					return;
				}
			}
			stillPurchasing = false;
		}
		// Update dialogue with property selection phase status.
		updateDialogue();
	}

	/**
	 * Confirms the purchase of selected property with the player.
	 * 
	 * @param cost
	 *            The cost of the selected property.
	 * @return True if the player confirms, false otherwise.
	 */
	public boolean confirmPropertySelection(Inventory cost) {
		int money = cost.getAmount(Resource.MONEY);
		return MuleDriver.showConfirmDialog(DIALOG_TITLE, "Purchase tile for $"
				+ money + "?");
	}

	/**
	 * Ends the property selection phase and starts the game.
	 */
	public void endPropertySelectionAndStartGame() {
		// Remove this listener from the application.
		this.view.removeKeyListener(this);
		MapPanel mapPanel = (MapPanel) MuleDriver.getMapLogic().getView();
		mapPanel.setResourceTileListener(null);
		// Start game.
		MuleDriver.getGameLogic().startGame();
	}

	/**
	 * Event handler tailored to listen to clicks on the map panel.
	 * 
	 * @param e
	 *            Event that was fired from the panel.
	 */
	public void actionPerformed(ActionEvent e) {
		// Get selected tile.
		ResourceTile resourceTile = (ResourceTile) e.getSource();
		// Make sure tile is purchasable.
		if (resourceTile.isPurchasable()) {
			Inventory tileCost;
			if (freeGrant) {
				// Price of land during free grant is zero resources.
				tileCost = new Inventory(0, 0, 0, 0, 0);
			} else {
				// Calculate cost of tile.
				tileCost = LandOfficeLogic.calcSellingPrice(0);
			}
			// Make sure player has enough resources to purchase the tile.
			if (currentPlayer.getInventory().hasResources(tileCost)) {
				// Confirm property selection.
				if (!confirmPropertySelection(tileCost)) {
					return;
				}
				// Purchase land and update scoreboard.
				LandOffice.purchaseLand(currentPlayer, resourceTile, tileCost);
				MuleDriver.updateScore(currentPlayer);
				// Go to next turn.
				stillPurchasing = true;
				nextTurn();
			} else {
				// Player does not have enough resources.
				MuleDriver.showAlertDialog(DIALOG_TITLE,
						"Insufficient resources to purchase tile!");
			}
		} else {
			// Tile is already owned -- not purchasable.
			MuleDriver.showAlertDialog(DIALOG_TITLE,
					"Someone already owns that tile!");
		}
	}

	/**
	 * Listens to key presses -- specifically the pass option key.
	 * 
	 * @param event
	 *            The event which was fired from the keyboard.
	 */
	public void keyPressed(KeyEvent event) {
		// Pass option is pressed.
		if (event.getKeyCode() == PASS_OPT_KEYCODE) {
			// Go to next turn.
			nextTurn();
		}
	}

	@Override
	public void keyReleased(KeyEvent event) {
	}

	@Override
	public void keyTyped(KeyEvent event) {
	}
}
